View Javadoc
1 /* 2 * Angkor Web Framework 3 * 4 * Distributable under LGPL license. 5 * See terms of license at gnu.org. 6 */ 7 package com.tirsen.angkor.table; 8 9 import com.tirsen.angkor.Debug; 10 import com.tirsen.angkor.RenderContext; 11 import com.tirsen.angkor.View; 12 import com.tirsen.angkor.event.ChangeEvent; 13 import com.tirsen.angkor.event.ChangeListener; 14 import com.tirsen.angkor.widget.Container; 15 import com.tirsen.angkor.widget.ValueModel; 16 import org.apache.log4j.Category; 17 18 import java.io.IOException; 19 import java.util.ArrayList; 20 import java.util.Collection; 21 import java.util.Iterator; 22 import java.util.List; 23 24 /*** 25 * The table should support the following features: 26 * Implemented ones: 27 * <li> Fetch values from the model. 28 * <li> A default cell-view-factory. 29 * <li> Cell-view-factories for each column overriding the default one. 30 * <li> Cell-view-factories for rows not getting values from the model. 31 * (for example a column for executing actions on the object on the row or for marking rows to remove) 32 * TODOs: 33 * <li> Row-view-factories for rows not getting values from the model. 34 * (for example a last line for adding new objects) 35 * <li> Inserting view-only view-factories before and after columns and rows. 36 * 37 * The implicit model and view-only row-view-factories and column-view-factories will probably 38 * be refactored into a TableColumn-class instead. The TableColumn-class has an index into the model 39 * if it is from the model and a view-factory for the cells. This way columns can be arranged in any order 40 * and still maintain a simple link to the model. This does not support the view-only rows so oftenly 41 * used on the web for creating a new row in the model, ie. a view-only row is not supported 42 * (in contrast to the view-only columns which are supported). 43 * 44 * @author $Author: tirsen $ 45 * @version $Revision: 1.5 $ 46 * <BR> 47 * $Id: Table.java,v 1.5 2002/10/09 21:37:37 tirsen Exp $ 48 */ 49 public class Table extends Container 50 { 51 private static final Category logger = Debug.getCategory(); 52 53 private TableModel model; 54 private TableCellViewFactory viewFactory; 55 private boolean readOnly = true; 56 57 /*** 58 * The created views are cached so that errors and other view-state can be displayed. 59 */ 60 private List views; 61 62 /*** 63 * A list of <code>TableColumn</code>s. 64 */ 65 private List tableColumns; 66 67 public Table() 68 { 69 this(true); 70 } 71 72 public Table(boolean readOnly) 73 { 74 this.readOnly = readOnly; 75 } 76 77 private ChangeListener resetCreatedViewsListener = new ChangeListener() 78 { 79 public void stateChanged(ChangeEvent evt) 80 { 81 System.out.println("resetting"); 82 resetCreatedViews(); 83 } 84 }; 85 86 public void setModel(TableModel model) 87 { 88 if (this.model != null) this.model.removeChangeListener(resetCreatedViewsListener); 89 this.model = model; 90 if (this.model != null) this.model.addChangeListener(resetCreatedViewsListener); 91 resetCreatedViews(); 92 createTableColumns(); 93 } 94 95 public List getRowViews(int row) 96 { 97 maybeCreateCellViews(); 98 List cells = (List) views.get(row - getStartRow()); 99 100 return cells; 101 } 102 103 public void setReadOnly(boolean readOnly) 104 { 105 this.readOnly = readOnly; 106 } 107 108 private void maybeCreateCellViews() 109 { 110 if (views == null) 111 { 112 logger.debug("recreating table cell views"); 113 createCellViews(); 114 } 115 } 116 117 private void createCellViews() 118 { 119 int capacity = getEndRow() - getStartRow() + 1; 120 views = new ArrayList(capacity); 121 int end = getEndRow(); 122 for (int row = getStartRow(); row <= end; row++) 123 { 124 int columns = getColumnCount(); 125 Collection cells = new ArrayList(columns); 126 127 for (int columnIndex = 0; columnIndex < columns; columnIndex++) 128 { 129 TableColumn column = getTableColumn(columnIndex); 130 131 if (column.isVisible()) 132 { 133 View view = column.getCellView(this, row, columnIndex); 134 view.setContainer(this); 135 cells.add(view); 136 } 137 } 138 views.add(cells); 139 } 140 } 141 142 public View getCellView(int row, int column) 143 { 144 return (View) getRowViews(row).get(column); 145 } 146 147 private TableColumn getTableColumn(int column) 148 { 149 return (TableColumn) tableColumns.get(column); 150 } 151 152 public ValueModel getCellModel(int row, int column) 153 { 154 TableColumn tableColumn = getTableColumn(column); 155 return tableColumn.getCellModel(row); 156 } 157 158 /*** 159 * Call this method when we have a suspicion that cell-views will need to be recreated. 160 */ 161 public void resetCreatedViews() 162 { 163 views = null; 164 } 165 166 public List getChildren() 167 { 168 List all = super.getChildren(); 169 for (Iterator iterator = views.iterator(); iterator.hasNext();) 170 { 171 List cells = (List) iterator.next(); 172 all.addAll(cells); 173 } 174 return all; 175 } 176 177 private TableCellViewFactory createDefaultTableCellViewFactory() 178 { 179 if (readOnly) 180 return new ReadOnlyCellViewFactory(); 181 else 182 return new DefaultTableCellViewFactory(); 183 } 184 185 public TableCellViewFactory getViewFactory() 186 { 187 if (viewFactory == null) viewFactory = createDefaultTableCellViewFactory(); 188 return viewFactory; 189 } 190 191 /*** 192 * Creates all TableColumns based upon the TableModel. 193 * These can be modified <em>after</em> setting the model. 194 * When the model is set the table-columns are recreated. 195 */ 196 private void createTableColumns() 197 { 198 int columns = getTableModel().getColumnCount(); 199 tableColumns = new ArrayList(columns); 200 for (int column = 0; column < columns; column++) 201 { 202 TableColumn tableColumn = new TableColumn(getTableModel(), column); 203 tableColumn.setViewFactory(getViewFactory()); 204 addTableColumn(tableColumn); 205 } 206 } 207 208 public void setTableCellViewFactory(TableCellViewFactory viewFactory) 209 { 210 this.viewFactory = viewFactory; 211 } 212 213 public int getRowCount() 214 { 215 return getTableModel().getRowCount(); 216 } 217 218 /*** 219 * Returns the number of columns table. 220 * Note that this is necessarily not the same number of columns as in the model. 221 */ 222 public int getColumnCount() 223 { 224 return tableColumns == null ? 0 : tableColumns.size(); 225 } 226 227 public TableModel getTableModel() 228 { 229 if (model == null) model = createDefaultTableModel(); 230 return model; 231 } 232 233 protected TableModel createDefaultTableModel() 234 { 235 return new DefaultTableModel(); 236 } 237 238 public String getColumnName(int column) 239 { 240 return getTableModel().getColumnName(column); 241 } 242 243 /*** 244 * If any number is set to a negative number it is subtracted from the number of rows. 245 * As a special case of this setting end to -1 sets the range to end at the last row. 246 * If end is lower or equal to start sets the range to show all. 247 */ 248 public void setRange(int start, int end) 249 { 250 resetCreatedViews(); 251 if (end <= start) 252 { 253 start = 0; 254 end = -1; 255 } 256 model.setRange(start, end); 257 } 258 259 /*** 260 * Insert a new column at the specified index. 261 */ 262 public void addTableColumn(int index, TableColumn column) 263 { 264 resetCreatedViews(); 265 tableColumns.add(index, column); 266 column.addChangeListener(resetCreatedViewsListener); 267 } 268 269 /*** 270 * Add a new column at the end. 271 */ 272 public void addTableColumn(TableColumn column) 273 { 274 if (tableColumns == null) tableColumns = new ArrayList(); 275 resetCreatedViews(); 276 tableColumns.add(column); 277 column.addChangeListener(resetCreatedViewsListener); 278 } 279 280 public void setColumnCellViewFactory(int column, TableCellViewFactory columnFactory) 281 { 282 if (tableColumns == null) tableColumns = new ArrayList(); 283 resetCreatedViews(); 284 TableColumn tableColumn = getTableColumn(column); 285 tableColumn.setViewFactory(columnFactory); 286 } 287 288 public int getStartRow() 289 { 290 return model.getStart(); 291 } 292 293 public int getEndRow() 294 { 295 return model.getEnd(); 296 } 297 298 private int scrollStart = 0; 299 private int scrollEnd = 0; 300 private int scrollNumberOfRows = 0; 301 302 public void scrollToStart() 303 { 304 scrollStart = 0; 305 scrollEnd = scrollNumberOfRows - 1; 306 setRange(scrollStart, scrollEnd); 307 } 308 309 public void scrollForward() 310 { 311 scrollStart += scrollNumberOfRows; 312 scrollEnd += scrollNumberOfRows; 313 setRange(scrollStart, scrollEnd); 314 } 315 316 public void scrollBackward() 317 { 318 scrollStart -= scrollNumberOfRows; 319 scrollEnd -= scrollNumberOfRows; 320 setRange(scrollStart, scrollEnd); 321 } 322 323 /*** 324 * Sets the maximum number of rows for scrolling. If set to 0 disables scrolling (ie. shows all). 325 * A call to this method automatically scrolls to the start of the table. 326 */ 327 public void setNumberOfScrollRows(int numberOfRows) 328 { 329 this.scrollNumberOfRows = numberOfRows; 330 scrollToStart(); 331 } 332 333 public void render(RenderContext context) throws IOException 334 { 335 context.startTag("table id=\"" + uniqueId(context) + "\" border=\"" + (isDebugTables() ? "1" : "0") + "\""); 336 337 //int modelColumns = getTableModel().getColumnCount(); 338 339 context.startTag("tr"); 340 for (int columnIndex = 0; columnIndex < getColumnCount(); columnIndex++) 341 { 342 TableColumn column = getTableColumn(columnIndex); 343 if (column.isVisible()) 344 { 345 String name = column.getColumnName(); 346 context.startTag("th"); 347 if (name != null) 348 context.println(name); 349 else 350 context.println(" "); 351 context.endTag("th"); 352 } 353 } 354 context.endTag("tr"); 355 356 int endRow = getEndRow(); 357 for (int row = getStartRow(); row <= endRow; row++) 358 { 359 context.startTag("tr"); 360 Iterator iterator = getRowViews(row).iterator(); 361 while (iterator.hasNext()) 362 { 363 View cell = (View) iterator.next(); 364 context.startTag("td"); 365 cell.render(context); 366 context.endTag("td"); 367 } 368 context.endTag("tr"); 369 } 370 context.endTag("table"); 371 } 372 }

This page was automatically generated by Maven